<?php
/**
* phpCan - http://idc.anavallasuiza.com/
*
* phpCan is released under the GNU Affero GPL version 3
*
* More information at license.txt
*/

namespace files;

defined('ANS') or die();

class File {
	public $folder;

	private $Debug;


	/**
	 * private function __construct()
	 */
	public function __construct() {
		global $Debug;

		$this->Debug = $Debug;
	}


	/**
	 * public function setFolder (string $folder, [boolean $make_if_not_exists])
	 *
	 * return boolean
	 */
	public function setFolder ($folder, $make_if_not_exists = false) {
		if ($make_if_not_exists) {
			$ok = $this->makeFolder($folder);
		} else {
			$ok = is_dir($folder);
		}

		if ($ok) {
			$this->folder = $folder;
		}

		return $ok;
	}


	/**
	 * public function makeFolder (string $folder, [int $permissions])
	 *
	 * return boolean
	 */
	public function makeFolder ($folder, $permissions = 0755) {
		if (is_dir($folder)) {
			return true;
		}

		if (is_file($folder)) {
			$this->Debug->error('file', __('The folder "%s" just exists as a file', $folder));
			return false;
		}

		$folder = preg_replace(array('#/?\.+/#', '#/+#'), '/', str_replace('\\', '/', $folder));
		$rel_folder = preg_replace('|^'.BASE_PATH.'|', '', $folder.'/');

		$dirs = explode('/', $rel_folder);
		$dir = BASE_PATH;

		foreach ($dirs as $part) {
			if (empty($part)) {
				continue;
			}

			$dir .= '/'.$part;

			if (!is_dir($dir)) {
				if (!@mkdir($dir, $permissions)) {
					$this->Debug->error('file', __('There was an error creating the folder "%s"', $dir));

					return false;
				}
			}
		}

		clearstatcache();

		if (is_dir($folder)) {
			return true;
		} else {
			return false;
		}
	}


	/**
	 * public function delete (string $folder)
	 *
	 * return boolean
	 */
	public function delete ($folder) {
		if (is_file($folder)) {
			return unlink($folder);
		}

		if (is_dir($folder)) {
			$folder = dirname($folder . '/.').'/';
			$handle = opendir($folder);

			while (($file = readdir($handle)) !== false) {
				if ($file == '.' || $file == '..') {
					continue;
				}

				$this->delete($folder.$file);
			}

			closedir($handle);
		}

		if (is_dir($folder)) {
			rmdir($folder);
		}
	}


	/**
	 * public function save (string/array $file, [string $destination], [string $filename])
	 *
	 * save a file from post or url
	 *
	 * return false/string
	 */
	public function save ($file, $destination = '', $filename = '') {
		if (!$file) {
			return false;
		}

		//Set folder
		if (!$destination) {
			$destination = $this->folder;
		} else if (!$filename) {
			$filename = pathinfo($destination, PATHINFO_BASENAME);
			$destination = pathinfo($destination, PATHINFO_DIRNAME).'/';
		}

		if (!$this->setFolder($destination, true)) {
			return false;
		}

		//Save post file
		if (is_array($file)) {
			if (!$file['size'] || !is_file($file['tmp_name'])) {
				return false;
			}

			if (!$filename) {
				$filename = $file['name'];
			}

			if (move_uploaded_file($file['tmp_name'], $destination.$filename)) {
				return $this->fixExtension($destination.$filename);
			}

			return false;
		}

		//Save url file
		if (!$filename) {
			$filename = pathinfo($file, PATHINFO_BASENAME);
		}

		if (copy($file, $destination.$filename)) {
			return $this->fixExtension($destination.$filename);
		}

		return false;
	}
	
	
	/**
	 * private function fixExtension (string $filename)
	 *
	 * return text
	 */
	public function fixExtension ($filename) {
		if (!pathinfo($filename, PATHINFO_EXTENSION)) {
			$ext = end(explode('/', $this->getMimeType($filename)));
			rename($filename, $filename.'.'.$ext);
			$filename .= '.'.$ext;
		}

		return $filename;
	}


	/**
	 * public function saveText (string $text, string $destination, [string $filename])
	 *
	 * save text into a file
	 *
	 * return boolean
	 */
	public function saveText ($text, $destination, $filename = '') {
		if (!$filename) {
			$filename = pathinfo($destination, PATHINFO_BASENAME);
			$destination = pathinfo($destination, PATHINFO_DIRNAME).'/';
		}

		if (!$this->setFolder($destination, true)) {
			return false;
		}

		return (file_put_contents($destination.$filename, $text) === false) ? false : $destination.$filename;
	}


	/**
	 * public function getMimeType (string $file, [string $compare])
	 *
	 * return false/string
	 */
	public function getMimeType ($file, $compare = '') {
		if (!$file || !is_file($file)) {
			return false;
		}

		$finfo = finfo_open(FILEINFO_MIME_TYPE);
		$mime_type = finfo_file($finfo, $file);
		finfo_close($finfo);

		if (is_array($compare)) {
			return in_array($mime_type, $compare);
		}

		if ($compare) {
		    return ($compare == $mime_type) ? true : false;
		}

		return $mime_type;
	}


	/**
	 * public function mergeFolder (string $source, [string $destination], [array $options], [array &$actions])
	 *
	 * return boolean
	 */
	public function mergeFolders ($source, $destination = null, $options = array(), &$actions = array()) {
		if (is_null($destination)) {
			$destination = $this->folder;
		}

		if (!is_array($actions)) {
			$actions = array();
		}

		$source = dirname($source . '/.').'/';
		$destination = dirname($destination . '/.').'/';

		$source_files = glob($source.'*', GLOB_MARK);
		$destination_files = glob($destination.'*', GLOB_MARK);

		$sub_options = $options;
		$sub_options['test_mode'] = true;

		foreach ($source_files as $file) {
			if (!$this->_checkFileAction($file, $destination, $destination_files, $options, $actions)) {
				continue;
			}

			if (substr($file, -1) == '/') {
				$this->mergeFolders($file, $destination.end(explode('/', $file, -1)), $sub_options, $actions);
			}
		}

		if ($options['delete']) {
			foreach ($destination_files as $file) {
				if (!$this->_checkFileAction($file, $source, $source_files, $options, $actions, true)) {
					continue;
				}
			}
		}

		if (!$options['test_mode']) {
			foreach ($actions as $action) {
				switch ($action['action']) {
					case 'make_folder':
						$this->makeFolder($action['to']);
						break;

					case 'copy_file':
					case 'replace':
						$this->save($action['from'], $action['to']);
						break;

					case 'delete':
						$this->delete($action['to']);
						break;
				}
			}
		}
	}


	/**
	 * private function _checkFileAction (string $file, string $destination, array $destination_files, array $options, array &$actions, [bool $inverted])
	 *
	 * return boolean
	 */
	private function _checkFileAction ($file, $destination, $destination_files, $options, &$actions, $inverted = false) {
		if ($options['ignore']) {
			if (preg_match($options['ignore'], $file)) {
				$actions[] = array(
					'action' => 'ignore',
					'from' => $file
				);

				return false;
			}
		}

		if ($options['filter']) {
			if (!preg_match($options['filter'], $file)) {
				$actions[] = array(
					'action' => 'no_filter',
					'from' => $file
				);

				return false;
			}
		}

		if (substr($file, -1) == '/') {
			$destination = $destination.end(explode('/', $file, -1)).'/';
			$type = 'folder';
		} else {
			$destination = $destination.pathinfo($file, PATHINFO_BASENAME);
			$type = 'file';
		}

		if ($inverted && !in_array($destination, $destination_files)) {
			$actions[] = array(
				'action' => 'delete',
				'to' => $file
			);

			return false;
		}

		if (!in_array($destination, $destination_files)) {
			if (!$options['no_make']) {
				$actions[] = array(
					'action' => ($type == 'file') ? 'copy_file' : 'make_folder',
					'from' => $file,
					'to' => $destination
				);
			}

			return true;
		}

		if ($options['replace'] && $type == 'file') {
			$actions[] = array(
				'action' => 'replace',
				'from' => $file,
				'to' => $destination
			);
		}

		return true;
	}
}
?>